package com.tiancikeji.zaoke.app.biz.impl;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import org.apache.commons.lang.time.DateUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.transaction.annotation.Transactional;

import com.tiancikeji.zaoke.app.biz.OrderBiz;
import com.tiancikeji.zaoke.app.exception.PayBalanceException;
import com.tiancikeji.zaoke.app.exception.PayURLException;
import com.tiancikeji.zaoke.app.model.food.Food;
import com.tiancikeji.zaoke.app.model.food.FoodPrice;
import com.tiancikeji.zaoke.app.model.order.Order;
import com.tiancikeji.zaoke.app.model.order.OrderFood;
import com.tiancikeji.zaoke.app.model.order.PayMode;
import com.tiancikeji.zaoke.app.model.order.PayRedirect;
import com.tiancikeji.zaoke.app.model.user.User;
import com.tiancikeji.zaoke.app.model.zone.Zone;
import com.tiancikeji.zaoke.app.service.bill.BillOrderService;
import com.tiancikeji.zaoke.app.service.order.OrderService;
import com.tiancikeji.zaoke.app.service.pay.PayService;
import com.tiancikeji.zaoke.app.service.user.UserService;
import com.tiancikeji.zaoke.app.util.ZaokeUtils;

public class OrderBizImpl implements OrderBiz {
	
	private PayService payService;
	
	private OrderService orderService;
	
	private BillOrderService billOrderService;
	
	private UserService userService;
	
	private Log logger = LogFactory.getLog(getClass());

	public List<PayMode> getPayMode(String os) {
		List<PayMode> modes = new ArrayList<PayMode>();
		
		List<PayMode> tmp = payService.getPayMode(os);
		if(tmp != null && tmp.size() > 0)
			for(PayMode mode : tmp)
				if(!mode.isDisable())
					modes.add(mode);
		
		return modes;
	}

	public Order getOrderById(long orderid, long userid) {
		return orderService.getOrderById(orderid, userid);
	}

	@Transactional(rollbackFor=Exception.class, value="txManager")
	public boolean cancelOrder(Order order) {
		boolean result = false;
		if(order != null){
			if(order.getState() == Order.STATE_CANCEL)
				return true;
			
			if(order.getState() == Order.STATE_TOKEN || order.getState() == Order.STATE_PAID_EXPIRE || order.getState() == Order.STATE_UNPAID_EXPIRE)
				return false;
			
			result = orderService.cancelOrder(order);
			if(result && order.getState() == Order.STATE_PAID){
				logger.info("cancel order <" + order + ">");
				result = userService.addBalance(order.getUserId(), order.getSalePrice());
				logger.info("added into user balance <" + order.getSalePrice() + ">.");
			}
		}
		
		return result;
	}

	public List<Order> getActiveOrdersByUserId(long userId) {
		List<Order> result = new ArrayList<Order>();
		if(userId > 0){
			List<Order> orders = orderService.getActiveOrdersByUserId(userId);
			
			if(orders != null && orders.size() > 0)
				for(Order order : orders)
					if(order != null && order.getUserId() == userId && order.getZoneId() > 0 && ((order.getPayWay() == 0 && order.getState() == Order.STATE_UNPAID) || (order.getPayWay() >= 0 && order.getState() == Order.STATE_PAID)))
						if(order.getOrderFood() != null && order.getOrderFood().size() > 0 && order.getOrderFood().size() <= 2)
							result.add(order);
		}
		
		return result;
	}

	@Transactional(rollbackFor=Exception.class, value="txManager")
	public Order createOrder(Food food1, Food food2, FoodPrice price, PayMode mode, Zone zone, User user, String system) throws PayURLException, PayBalanceException {
		Order order = null;
		if((food1 != null || food2 != null) && price != null && mode != null && zone != null && user != null){
			order = new Order();
			Date now = new Date();
			long orderId = orderService.geneOrderId(now, zone.getId());
			logger.debug("generating orderId <" + orderId + "> for now <" + now + "> zone <" + zone.getId() + ">");
			
			List<OrderFood> foods = new ArrayList<OrderFood>();
			if(food1 != null){
				OrderFood food = new OrderFood();
				food.setOrderId(orderId);
				food.setUserId(user.getUserId());
				food.setFoodId(food1.getId());
				food.setFoodName(food1.getName());
				food.setFoodType(food1.getType());
				food.setSalePrice(food1.getSalePrice());
				foods.add(food);
			}
			if(food2 != null){
				OrderFood food = new OrderFood();
				food.setOrderId(orderId);
				food.setUserId(user.getUserId());
				food.setFoodId(food2.getId());
				food.setFoodName(food2.getName());
				food.setFoodType(food2.getType());
				food.setSalePrice(food2.getSalePrice());
				foods.add(food);
			}
			
			order.setOrderId(orderId);
			order.setUserId(user.getUserId());
			order.setUserName(user.getUserName());
			order.setZoneId(zone.getId());
			if(price.getPromotionPrice() > 0)
				order.setSalePrice(price.getPromotionPrice());
			else if(price.getComboPrice() > 0)
				order.setSalePrice(price.getComboPrice());
			else
				order.setSalePrice(price.getSalePrice());
			
			if(mode.getMode() == PayMode.MODE_BALANCE && order.getSalePrice() > user.getBalance())
				throw new PayBalanceException();
			
			order.setPayWay(mode.getMode());
			order.setState(Order.STATE_UNPAID);
			order.setOrderTime(now);
			try {
				order.setBookTime(new SimpleDateFormat("yyyy年MM月dd日 HH:mm").parse(ZaokeUtils.getPickDate() + " " + zone.getPickStartTime()));
			} catch (ParseException e) {
				order.setBookTime(DateUtils.addDays(now, 1));
			}
			order.setOrderFood(foods);
			
			if(!orderService.createOrder(order)){
				order = null;
				return order;
			}
			logger.debug("after generationg order <" + order + ">");
			
			if(mode.getMode() == PayMode.MODE_ALI_APP || mode.getMode() == PayMode.MODE_ALI_WAP || mode.getMode() == PayMode.MODE_ALI_WEB){
				PayRedirect pay = billOrderService.genBill(order, system);
				logger.debug("after generationg bill <" + pay + ">");
				if(pay.isGateway()){
					if(mode.getMode() == PayMode.MODE_ALI_APP || mode.getMode() == PayMode.MODE_ALI_WAP)
						order.setUrl(pay.getWapUrl());
					else if(mode.getMode() == PayMode.MODE_ALI_WEB)
						order.setUrl(pay.getWebUrl());
				} else
					throw new PayURLException();
			}
			
			if(mode.getMode() == PayMode.MODE_BALANCE){
				// substract from balance
				if(userService.addBalance(user.getUserId(),  - order.getSalePrice(), user.getBalance())){
					boolean result = orderService.payOrder(orderId);
					user.setBalance(user.getBalance() - order.getSalePrice());
					logger.debug("after paying order [" + result + "] for order <" + order + ">.");
				} else
					throw new PayBalanceException();
			}
			
			userService.updateUserOrder(user.getUserId(), order.getOrderTime(), order.getZoneId(), order.getPayWay());
		}
		return order;
	}

	@Transactional(rollbackFor=Exception.class, value="txManager")
	public Order recharge(double money, PayMode mode, User user, String system) throws PayURLException {
		Order order = null;
		if(money > 0 && mode != null && user != null){
			order = new Order();
			Date now = new Date();
			long orderId = orderService.geneOrderId(now, 0);
			logger.debug("generating orderId <" + orderId + "> for now <" + now + "> recharge <" + 0 + ">");
			
			order.setOrderId(orderId);
			order.setUserId(user.getUserId());
			order.setUserName(user.getUserName());
			order.setZoneId(0);
			order.setSalePrice(money);
			order.setPayWay(mode.getMode());
			order.setState(Order.STATE_UNPAID);
			order.setOrderTime(now);
			order.setBookTime(now);
			
			if(!orderService.recharge(order)){
				order = null;
				return order;
			}
			logger.debug("after generationg order <" + order + ">");
			
			if(mode.getMode() == PayMode.MODE_ALI_APP || mode.getMode() == PayMode.MODE_ALI_WAP || mode.getMode() == PayMode.MODE_ALI_WEB){
				PayRedirect pay = billOrderService.genBill(order, system);
				logger.debug("after generationg bill <" + pay + ">");
				if(pay.isGateway()){
					if(mode.getMode() == PayMode.MODE_ALI_APP || mode.getMode() == PayMode.MODE_ALI_WAP)
						order.setUrl(pay.getWapUrl());
					else if(mode.getMode() == PayMode.MODE_ALI_WEB)
						order.setUrl(pay.getWebUrl());
				} else
					throw new PayURLException();
			}
		}
		return order;
	}

	public PayService getPayService() {
		return payService;
	}

	public void setPayService(PayService payService) {
		this.payService = payService;
	}

	public OrderService getOrderService() {
		return orderService;
	}

	public void setOrderService(OrderService orderService) {
		this.orderService = orderService;
	}

	public BillOrderService getBillOrderService() {
		return billOrderService;
	}

	public void setBillOrderService(BillOrderService billOrderService) {
		this.billOrderService = billOrderService;
	}

	public UserService getUserService() {
		return userService;
	}

	public void setUserService(UserService userService) {
		this.userService = userService;
	}
}
